package com.tbvtc.agriculturalcreditchainserver2025.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.tbvtc.agriculturalcreditchainserver2025.Json.Pesticide;
import com.tbvtc.agriculturalcreditchainserver2025.async.AsyncQueryService;
import com.tbvtc.agriculturalcreditchainserver2025.dto.CropDto;
import com.tbvtc.agriculturalcreditchainserver2025.dto.LandDto;
import com.tbvtc.agriculturalcreditchainserver2025.dto.farmer.registerCropDto;
import com.tbvtc.agriculturalcreditchainserver2025.entity.*;
import com.tbvtc.agriculturalcreditchainserver2025.exception.FoodException;
import com.tbvtc.agriculturalcreditchainserver2025.mapper.CropImageMapper;
import com.tbvtc.agriculturalcreditchainserver2025.mapper.CropMapper;
import com.tbvtc.agriculturalcreditchainserver2025.mapper.CropRecordsMapper;
import com.tbvtc.agriculturalcreditchainserver2025.mapper.FarmerMapper;
import com.tbvtc.agriculturalcreditchainserver2025.pojo.*;
import com.tbvtc.agriculturalcreditchainserver2025.properties.ContractAdressProperties;
import com.tbvtc.agriculturalcreditchainserver2025.service.*;
import com.tbvtc.agriculturalcreditchainserver2025.utils.*;
import com.tbvtc.agriculturalcreditchainserver2025.utils.Pest.PestHttpUtils;
import com.tbvtc.agriculturalcreditchainserver2025.utils.Pest.PestUtils;
import com.tbvtc.agriculturalcreditchainserver2025.utils.Pest.PesticideReportGenerator;
import com.tbvtc.agriculturalcreditchainserver2025.utils.huawei.HwCloudIot;
import com.tbvtc.agriculturalcreditchainserver2025.utils.redis.CacheClient;
import com.tbvtc.agriculturalcreditchainserver2025.constant.RedisConstant;
import com.tbvtc.agriculturalcreditchainserver2025.vo.farmerVo.FoodMessage;
import com.tbvtc.agriculturalcreditchainserver2025.vo.farmerVo.FoodReportVo;
import io.ipfs.api.IPFS;
import lombok.extern.slf4j.Slf4j;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.fisco.bcos.sdk.transaction.model.exception.TransactionBaseException;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FarmerServiceImpl implements FarmerSerive {

    @Autowired
    private BlockBaseUtils blockBaseUtils;
    @Autowired
    private BlockchainUtils blockchainUtils;
    @Autowired
    private RoleAddress roleAddress;
    @Autowired
    private ContractAdressProperties contractAdressProperties;
    @Autowired
    private FarmerMapper farmerMapper;
    @Autowired
    private CropMapper cropMapper;
    @Autowired
    private CropImageMapper cropImageMapper;
    @Autowired
    private PestDiseaseDamage pestDiseaseDamage;
    @Autowired
    private AsyncQueryService asyncQueryService;
    @Resource
    private CacheClient cacheClient;
    @Resource
    private HwCloudIot himCloudI;
    @Resource
    private IFarmlandInfoService farmlandInfoService;
    @Resource
    private IUserService userService;
    @Resource
    private ICropService cropService;
    @Resource
    private ICropPesticideInfoService cropPesticideInfoService;
    @Resource
    private ICropFertilizerCheckService cropFertilizerCheckService;
    @Resource
    private PestHttpUtils pestHttpUtils;
    @Resource
    private PesticideReportGenerator pesticideReportGenerator;


    @Autowired
    @Qualifier("TredisTemplate")
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    //    @Autowired
//    private PreciseChinaClimateService climateService;
    @Value("${ipfs.config.multi-addr}")
    private String multiAddr;

    private IPFS ipfs;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate1;

    @PostConstruct  //  再加入ioc容器之前执行
    public void setMultiAddr() {
        ipfs = new IPFS(multiAddr);
    }

    /**
     * 注册作物
     *
     * @param registerCropDto
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TransactionResponse registerCrop(registerCropDto registerCropDto) throws Exception {
        String address = farmerMapper.selectAddress(registerCropDto.getUserId());
        registerCropDto.setCropName(registerCropDto.getCropName());
        registerCropDto.setCreateTime(LocalDateTime.now());
        FarmlandInfo info = farmlandInfoService.getById(registerCropDto.getLandId());
        User user = userService.getById(registerCropDto.getUserId());
        // 农作物入库
        Crop crop = BeanUtil.copyProperties(registerCropDto, Crop.class);
        crop.setName(registerCropDto.getCropName());
        crop.setLandName(info.getLandName());
        crop.setPhone(user.getPhone());
        crop.setIsSale(0);
        cropService.save(crop);
        // 更新是否种植状
        farmerMapper.isplanting(info.getLandName());
        List<Object> list = List.of(address, registerCropDto.getCropName(), registerCropDto.getCropCategory(), registerCropDto.getExpectedYield(), info.getLandName());
        return blockchainUtils.sendTransaction("CropManagement", "registerCrop", contractAdressProperties.getCropManagementAddress(), list, blockBaseUtils.getPemFilePath(UserType.FARMER));
    }

    /**
     * 初始化土地
     *
     * @param landInit
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public TransactionResponse initLand(landInit landInit) throws Exception {
        String address = farmerMapper.selectAddress(landInit.getId());
        List<Object> list = new ArrayList<>();
        list.add(address);
//        String type = climateService.getClimateType(landInit.getLatitude(), landInit.getLongitude());
        String landName = landInit.getLandName();
        landInit.setLandName(landName);
        list.add(landName);
        list.add(landInit.getLandsize());
        list.add(landInit.getLandQuality());
        list.add(landInit.getClimate()); // 气候
        list.add(landInit.getPreviousCro());
        landInit.setIsPlanting(0);
        landInit.setCreateTime(LocalDateTime.now());
        farmerMapper.addLand(landInit);
        TransactionResponse response = blockchainUtils.sendTransaction("LandManagement",
                "initializeLand",
                contractAdressProperties.getLandManagementAddress(),
                list, blockBaseUtils.getPemFilePath(UserType.ADMIN));
        return response;
    }

    /**
     * 上传作物图片
     *
     * @param landName
     * @return
     * @throws Exception
     */
    @Override
    public List getLandInfo(String landName) throws Exception {
        List<Object> list = new ArrayList<>();
        list.add(landName);
        List<Object> list1 = blockchainUtils.callContract("LandManagement", "lands", contractAdressProperties.getLandManagementAddress(), list, blockBaseUtils.getPemFilePath(UserType.FARMER));
        return list1;
    }

    /**
     * 物联
     *
     * @param iotInfo
     * @return
     * @throws Exception
     */
    @Override
    public TransactionResponse addIot(IotInfo iotInfo) throws Exception {
        String address = farmerMapper.selectAddress(iotInfo.getId());
        List<Object> list = List.of(address, iotInfo.getDeviceId(), iotInfo.getDeviceType(), iotInfo.getData());
        TransactionResponse response = blockchainUtils.sendTransaction("IoTManagement",
                "addIoTDevice",
                contractAdressProperties.getLoTManagementAddress(),
                list,
                blockBaseUtils.getPemFilePath(UserType.FARMER));
        return response;
    }

    //添加物联网设备
    @Override
    public List getIot(String deviceId) throws Exception {
        List<Object> list1 = List.of(deviceId);
        List<Object> list = blockchainUtils.callContract("IoTManagement", "iotDevices", contractAdressProperties.getLoTManagementAddress(), list1, blockBaseUtils.getPemFilePath(UserType.FARMER));
        IotList iotList = new IotList(list);
        return List.of(iotList);
    }

    // 更新物联网设备
    @Override
    public TransactionResponse updateIot(updateIotInfo updateIotInfo) throws Exception {
        String address = farmerMapper.selectAddress(updateIotInfo.getId());
        List<Object> list = List.of(address, updateIotInfo.getDeviceId(), updateIotInfo.getNewData());
        TransactionResponse response1 = blockchainUtils.sendTransaction("IoTManagement", "updateIoTDeviceData", contractAdressProperties.getLoTManagementAddress(), list, blockBaseUtils.getPemFilePath(UserType.FARMER));
//        TransactionResponse response =  blockchainUtils.sendTransaction("IoTManagement", "updateIoTDeviceData", contractAdressProperties.getLoTManagementAddress(), list, blockBaseUtils.getPemFilePath(UserType.FARMER));
        return response1;
    }

    /**
     * 添加田间档案
     *
     * @param cropDto
     * @return
     * @throws Exception
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TransactionResponse addReport(CropDto cropDto) throws Exception {
        //首先判断农族物是否成熟
        Crop crop = cropService.getOne(new LambdaUpdateWrapper<Crop>()
                .eq(Crop::getName, cropDto.getCropName())
        );
        if (crop.getIsMature().equals("1")){
            throw new FoodException(ResultCodeEnum.CROP_IS_MATURE);
        }
        stringRedisTemplate.opsForValue().set(RedisConstant.CROP_STAGE_TYPE + cropDto.getCropName(), cropDto.getReportType());
        Map<String, Double> temAndHumInfo = himCloudI.getTemAndHumInfo();//获取温湿度
        CropRecords cropRecords = BeanUtil.copyProperties(cropDto, CropRecords.class);
        cropRecords.setHumidity(temAndHumInfo.get("humidity").toString())
                .setTemperature(temAndHumInfo.get("temperature").toString())
                .setLightHours(himCloudI.getIlluminationValue())
                .setSoilHumidity(String.valueOf(himCloudI.getSoilMoistureInfo()));
        Gson gson = new Gson();
        // 使用 TypeToken 指定目标类型为 List<Pesticide>
        TypeToken<List<Pesticide>> typeToken = new TypeToken<>() {
        };
        List<Pesticide> pesticideList = gson.fromJson(cropDto.getPesticideRecords(), typeToken.getType());
         //将农药记录转换成List<Pesticide>存储进数据库
        extracted(cropDto, pesticideList);
        if (cropDto.getReportType().equals("成熟期")){
            //方法进行AI生成检测报告
            pesticideReportGenerator.getDetectionReport(crop.getId());
            crop.setIsMature("1");
            cropService.updateById(crop);
        }
        //上链
        List<Object> list = List.of(
                cropDto.getCropName(), // 农作物名称
                cropDto.getReportType(), // 报告类型
                cropDto.getGrowthPhotos(), // 成长照片
                cropRecords.getTemperature(), // 温度
                cropDto.getFertilizationRecords(), // 施肥记录
                cropDto.getPesticideRecords(), // 农药记录
                cropDto.getInspectionReport(), // 检查报告
                cropRecords.getHumidity(), // 湿度
                cropRecords.getLightHours().toString() // 日照
        );
        TransactionResponse response = blockchainUtils.sendTransaction(
                "FarmerManagement",
                "addCropReport",
                contractAdressProperties.getFarmerManagementAddress(),
                list,
                blockBaseUtils.getPemFilePath(UserType.FARMER));
        String key = RedisConstant.APP_ROOM_PREFIX + cropDto.getCropName();
        redisTemplate.delete(key); // 删除redis缓存
        return response;
    }

    private void extracted(CropDto cropDto, List<Pesticide> pesticideList) {
        pesticideList.forEach(pesticide -> {
            // 从数据库查询对应的CropPesticideInfo
            Long useCount = stringRedisTemplate.opsForValue().increment(cropDto.getCropName() + ":" + pesticide.getPesticideName());
            CropPesticideInfo cropPesticideInfo = cropPesticideInfoService.getOne(new LambdaQueryWrapper<CropPesticideInfo>()
                    .eq(CropPesticideInfo::getCropName, cropDto.getCropName())
                    .eq(CropPesticideInfo::getPesticideGenericName, pesticide.getPesticideName())
            );
            stringRedisTemplate.opsForValue().increment(cropDto.getCropName() + ":" + pesticide.getPesticideName());
            if (cropPesticideInfo==null){
                 return;
            }
            long remainingCount = cropPesticideInfo.getMaxApplicationTimes().longValue() - useCount;
            String dbConcRange = cropPesticideInfo.getActiveIngredientConc();
            String pesticideConc = pesticide.getNumber();
            stringRedisTemplate.opsForValue().increment(cropDto.getCropName() + ":" + pesticide.getPesticideName());
            // 解析区间，假设格式是“min~max”
            if (dbConcRange != null && pesticideConc != null) {
                String[] rangeArr = dbConcRange.split("～");
                if (rangeArr.length == 2) {
                    double min = Double.parseDouble(rangeArr[0].trim());
                    double max = Double.parseDouble(rangeArr[1].trim());
                    double conc = Double.parseDouble(pesticideConc.trim());
                    CropFertilizerCheck cropFertilizerCheck = new CropFertilizerCheck();
                    cropFertilizerCheck.setCropName(cropDto.getCropName())
                            .setFertilizerType(pesticide.getPesticideName())
                            .setFarmerDosage(pesticide.getNumber())
                            .setStandardDosage(cropPesticideInfo.getActiveIngredientConc())
                            .setReferenceBasis("GB/T 8321.10-2018《农药合理使用准则 (十)》标准")
                            .setStageType(cropDto.getReportType())
                    ;
                    if (conc >= min && conc <= max) {
                        //说明合格
                        cropFertilizerCheck.setIsQualified(true);
                        //传入ai农作物，农药，用了几次，是否合格
                        cropFertilizerCheck.setAiSuggestion(pestHttpUtils.getTreatmentMethodByAi(
                                cropDto.getCropName(),
                                pesticide.getPesticideName(),
                                pesticide.getNumber(),
                                remainingCount,
                                "合格没问题"));
                        cropFertilizerCheckService.save(cropFertilizerCheck);
                    } else if (conc < min) {
                        //浓度低了
                        cropFertilizerCheck.setIsQualified(false);
                        cropFertilizerCheck.setAiSuggestion(pestHttpUtils.getTreatmentMethodByAi(
                                cropDto.getCropName(),
                                pesticide.getPesticideName(),
                                pesticide.getNumber(),
                                remainingCount,
                                "不合格使用量低"));
                        cropFertilizerCheckService.save(cropFertilizerCheck);
                    } else { // 仅剩 conc > max 的情况
                        cropFertilizerCheck.setIsQualified(false);
                        cropFertilizerCheck.setAiSuggestion(pestHttpUtils.getTreatmentMethodByAi(
                                cropDto.getCropName(),
                                pesticide.getPesticideName(),
                                pesticide.getNumber(),
                                remainingCount,
                                "不合格使用量过高"));
                        cropFertilizerCheckService.save(cropFertilizerCheck);
                    }
                }
            }
        });
    }

    /**
     * 获取报告
     *
     * @param foodName
     * @return
     * @throws Exception
     */
    @Override
    public List<FoodReportVo> getReport(String foodName) {
//        List list = cacheClient.queryWithPassThrough(RedisConstant.APP_ROOM_PREFIX, foodName, List.class,
//                this::getFoodReportVos, RedisConstant.FOOD_TIME, TimeUnit.MINUTES);
        return getFoodReportVos(foodName);
    }

    @NotNull // 返回一个非空的结果
    private List<FoodReportVo> getFoodReportVos(String foodName) {
        List<Object> reportCountList = null;
        try {
            reportCountList = blockchainUtils.callContract(
                    "FarmerManagement",
                    "getReportCount",
                    contractAdressProperties.getFarmerManagementAddress(),
                    List.of(foodName),
                    blockBaseUtils.getPemFilePath(UserType.FARMER)
            );
        } catch (TransactionBaseException e) {
            e.printStackTrace();
            throw new FoodException(ResultCodeEnum.FAILED_TO_QUERY);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        BigInteger reportCountNum = (BigInteger) reportCountList.get(0);
        int reportNum = reportCountNum.intValue();
        List<CompletableFuture<FoodReportVo>> list = new ArrayList<>();
        for (int i = 0; i < reportNum; i++) {
            list.add(asyncQueryService.getCropReport(foodName, i));
        }
        // 合并所有Future
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                list.toArray(new CompletableFuture[0])
        );
        // 等待所有任务完成
        allFutures.join();
        List<FoodReportVo> results = new ArrayList<>();
        for (CompletableFuture<FoodReportVo> future : list) {
            results.add(future.join());
        }
        return results;
    }

    //标记农作物已经收获
    @Override
    public TransactionResponse markHarvested(String foodName) throws Exception {
        List<Object> list = List.of(foodName);
        //标记农作物已收货
        farmerMapper.ismatured(foodName);
        farmerMapper.updateActiveByLandName(farmerMapper.selectLandNameByFoodName(foodName));
        return blockchainUtils.sendTransaction("FarmerManagement", "markCropAsHarvested", contractAdressProperties.getFarmerManagementAddress(), list, blockBaseUtils.getPemFilePath(UserType.FARMER));
    }

    @Override
    public List selectFoodByPhone(String phone) {
        List<FoodMessage> list = farmerMapper.selectFoodByPhone(phone);
        return list;
    }

    //查询所有农作物
    @Override
    public List findAllCrop() {
        List<FoodMessage> allCrop = farmerMapper.findAllCrop();
        List<Crop> crops = cropMapper.selectList(null);
        List<CropImage> cropImageList = cropImageMapper.selectList(new LambdaQueryWrapper<CropImage>()
                .in(CropImage::getCropId, crops.stream().map(Crop::getId).collect(Collectors.toList())));
        return allCrop;
    }

    //查询所有土地
    @Override
    public List findAllLand(Integer id) {
        List<LandDto> allLand = farmerMapper.findAllLand(id);

        return allLand;
    }

    /**
     * 获取土地信息
     *
     * @param id
     * @return
     */
    @Override
    public landInit getLandInfoById(String id) {
        return farmerMapper.getLandById(id);
    }

    @Override
    public Double discount(Double discount, Double price) {
        return discount * price;

    }

    @Override
    public Crop findFoodById(Integer cropId) {

        return farmerMapper.selectCrop(cropId);

    }

    @Override
    public void markLandUsed(String landId, String isActive) {
        farmerMapper.markLandUsed(landId, isActive);
    }


}
